package tournoi.modele;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;

import tournoi.modele.Colonne.EtatColonne;

@Entity
public class Tournoi implements Serializable {

	private static final long serialVersionUID = 4452046780506782049L;

	public enum EtatTournoi {
		ATTENTE, ENCOURS, FINI
	};

	private int idTournoi;
	private String nomTournoi;
	private List<Colonne> phases;
	private EtatTournoi etat;
	private List<Equipe> lesEquipes;
	private int numeroPhase;

	public Tournoi() {
		super();
	}

	public Tournoi(String nomTournoi) {
		super();
		this.nomTournoi = nomTournoi;
		this.etat = EtatTournoi.ATTENTE;
		this.phases = new ArrayList<Colonne>();
		this.lesEquipes = new ArrayList<Equipe>();
		this.numeroPhase = 0;
	}

	@Id
	@GeneratedValue
	public int getIdTournoi() {
		return idTournoi;
	}

	public void setIdTournoi(int idTournoi) {
		this.idTournoi = idTournoi;
	}

	public String getNomTournoi() {
		return nomTournoi;
	}

	public void setNomTournoi(String nomTournoi) {
		this.nomTournoi = nomTournoi;
	}

	@OneToMany(targetEntity = Colonne.class, cascade = CascadeType.ALL)
	public List<Colonne> getPhases() {
		return phases;
	}

	public void setPhases(List<Colonne> phases) {
		this.phases = phases;
	}

	@ManyToMany(targetEntity = Equipe.class, cascade = { CascadeType.ALL })
	public List<Equipe> getLesEquipes() {
		return lesEquipes;
	}

	public void setLesEquipes(List<Equipe> lesEquipes) {
		this.lesEquipes = lesEquipes;
	}

	public EtatTournoi getEtat() {
		return etat;
	}

	public void setEtat(EtatTournoi etat) {
		this.etat = etat;
	}

	public int getNumeroPhase() {
		return numeroPhase;
	}

	public void setNumeroPhase(int numeroPhase) {
		this.numeroPhase = numeroPhase;
	}

	/*
	 * Méthodes pour la gestion du tournoi
	 */

	/**
	 * Création de toutes les phases et des rencontres
	 */
	private void remplirPremierePhase() {
		if (etat == EtatTournoi.ATTENTE) {
			List<Equipe> le = lesEquipes;
			// On mélange les équipes
			Collections.shuffle(le);
			/* Première colonne */
			Colonne premiere = new Colonne();
			premiere.setLesEquipes(le);
			/*
			 * On créé toute les rencontres avant afin de facilité l'affichage
			 */
			List<Rencontre> lr = new ArrayList<Rencontre>();
			for (int i = 0; i < le.size() / 2; i++) {
				Rencontre r = new Rencontre();
				r.setTournoi(idTournoi);
				lr.add(r);
			}
			premiere.setLesMatchs(lr);

			/* Création des phases */
			phases = new ArrayList<Colonne>();
			phases.add(premiere);
			numeroPhase = 0;

			/* création de toutes les autres phases */
			int nombrePhases = lesEquipes.size() / 2;
			while (nombrePhases >= 2) {
				Colonne c = new Colonne();
				/*
				 * On créé toute les rencontres avant afin de facilité
				 * l'affichage
				 */
				List<Rencontre> lr1 = new ArrayList<Rencontre>();
				for (int i = 0; i < nombrePhases / 2; i++) {
					Rencontre r = new Rencontre();
					r.setTournoi(idTournoi);
					lr1.add(r);
				}
				c.setLesMatchs(lr1);
				phases.add(c);

				nombrePhases = nombrePhases / 2;
			}

			/* Tournoi en cours on ne peut plus modifier les équipes */
			etat = EtatTournoi.ENCOURS;
		}
	}

	public void demarrer() {
		if (lesEquipes.size() >= 2) {
			remplirPremierePhase();
			phases.get(0).demarrerPhase();
		}
	}

	public String gagnant() {
		String gagnant = "-----";
		if (phases != null && !phases.isEmpty()) {
			Colonne c = phases.get(phases.size() - 1);
			if (c.getEtat() == EtatColonne.FINI) {
				gagnant = c.gagnants().get(0).getNomEquipe();
			}
		}
		return gagnant;
	}

	/**
	 * Démarre la phase suivante
	 */
	private void phaseSuivante() {
		Colonne col = phases.get(numeroPhase);
		if (etat == EtatTournoi.ENCOURS && col.termine()
				&& numeroPhase < phases.size() - 1) {
			numeroPhase++;
			List<Equipe> le = col.gagnants();
			Colonne next = phases.get(numeroPhase);
			next.setLesEquipes(le);
			next.demarrerPhase();
		}
	}

	/**
	 * Vérifie l'état du tournoi après un match terminé
	 */
	public void verifier() {
		Colonne c = phases.get(numeroPhase);
		if (c.verifier()) {
			phaseSuivante();
		}
		c = phases.get(numeroPhase);
		if (c.termine() && numeroPhase <= phases.size()) {
			etat = EtatTournoi.FINI;
		}
	}

	public String etat() {
		switch (etat) {
		case ATTENTE:
			return "Pas démarré";
		case ENCOURS:
			return "En cours";
		case FINI:
			return "Fini !";
		default:
			return "Pas démarré";
		}
	}
}
